﻿#include "Drawer.h"

#include <glm/gtc/type_ptr.hpp>

// 随机数生成辅助函数
float randRange(float min, float max) {
    static std::mt19937 gen(std::random_device{}());
    return std::uniform_real_distribution<float>(min, max)(gen);
}

int randInt(int min, int max) {
    static std::mt19937 gen(std::random_device{}());
    return std::uniform_int_distribution<>(min, max)(gen);
}

ParticleSystem Drawer::initParticles(
    glm::vec2 initRadius,
    glm::vec4 color,
    glm::vec2 lifeRange,
    float initCircleRadius,
    glm::vec2 velRange,
    glm::vec2 initAngleRange,
    glm::vec2 accelDeltaRange,
    glm::vec2 accelAngleRange,
    int particleTotal,
    float width,
    float height,
    float frameRate
) {
    ParticleSystem system;

    // 存储系统参数
    system.color = color;
    system.width = width;
    system.height = height;
    system.frameRate = frameRate;
    system.initRadius = initRadius;
    system.lifeRange = lifeRange;
    system.initCircleRadius = initCircleRadius;
    system.velRange = velRange;
    system.initAngleRange = initAngleRange;
    system.accelDeltaRange = accelDeltaRange;
    system.accelAngleRange = accelAngleRange;
    system.center = glm::vec2(width / 2, height / 2);

    // 初始化粒子容器
    system.particles.resize(particleTotal);
    for (auto& p : system.particles) {
        p.life = 0;
        p.radius = 0.0f;
    }

    // 初始化OpenGL资源
    glGenVertexArrays(1, &system.VAO);
    glGenBuffers(1, &system.VBO);

    glBindVertexArray(system.VAO);
    glBindBuffer(GL_ARRAY_BUFFER, system.VBO);
    glBufferData(GL_ARRAY_BUFFER, particleTotal * sizeof(glm::vec3), nullptr, GL_DYNAMIC_DRAW);

    // 设置顶点属性指针
    glEnableVertexAttribArray(0); // 位置
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenTextures(1, &system.tempTex);
    glBindTexture(GL_TEXTURE_2D, system.tempTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glGenFramebuffers(1, &system.tempFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, system.tempFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, system.tempTex, 0);

    // ==== 关键修复1：正确初始化多采样纹理 ====
    glGenTextures(1, &system.texture);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, system.texture);
    glTexImage2DMultisample(
        GL_TEXTURE_2D_MULTISAMPLE,
        1,                      // 采样数必须 ≥1（例如4）
        GL_RGBA8,
        width,
        height,
        GL_TRUE                 // 固定采样位置
    );

    glGenFramebuffers(1, &system.msaaFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, system.msaaFBO);
    glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_2D_MULTISAMPLE,
        system.texture,
        0
    );

    GLuint depthRBO;
    glGenRenderbuffers(1, &depthRBO);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRBO);
    glRenderbufferStorageMultisample(
        GL_RENDERBUFFER,
        1,
        GL_DEPTH24_STENCIL8,
        width,
        height
    );
    glFramebufferRenderbuffer(
        GL_FRAMEBUFFER,
        GL_DEPTH_STENCIL_ATTACHMENT,
        GL_RENDERBUFFER,
        depthRBO
    );

    // 检查多采样FBO完整性
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        std::cerr << "多采样FBO初始化失败！错误码："
            << glCheckFramebufferStatus(GL_FRAMEBUFFER) << std::endl;
    }

    // ==== 关键修复4：创建解析FBO（非多采样） ====
    glGenFramebuffers(1, &system.FBO);
    glGenTextures(1, &system.resolveTexture);
    glBindTexture(GL_TEXTURE_2D, system.resolveTexture);
    glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_RGBA8,              // 格式与多采样纹理一致
        width,
        height,
        0,
        GL_RGBA,
        GL_UNSIGNED_BYTE,
        nullptr
    );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glBindFramebuffer(GL_FRAMEBUFFER, system.FBO);
    glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_2D,
        system.resolveTexture,
        0
    );

    // 检查解析FBO完整性
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        std::cerr << "解析FBO初始化失败！错误码："
            << glCheckFramebufferStatus(GL_FRAMEBUFFER) << std::endl;
    }

    // 恢复默认FBO
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    system.projection = glm::ortho(0.0f, system.width, 0.0f, system.height);
    return system;
}

void Drawer::updateAndDrawParticles(
    GLuint shaderProgram,
    ParticleSystem& system,
    size_t particleCount
) {
    Utils::clearFrame(system.FBO);
    // 激活新粒子
    int activated = 0;
    for (auto& p : system.particles) {
        if (activated >= particleCount) break;
        if (p.life <= 0 && p.radius <= 0.0f) {
            p.life = randInt(system.lifeRange.x, system.lifeRange.y);
            p.radius = randRange(system.initRadius.x, system.initRadius.y);
            float angle = randRange(0.0f, 2 * M_PI);
            p.position = glm::vec2(
                system.initCircleRadius * cosf(angle) + system.center.x,
                system.initCircleRadius * sinf(angle) + system.center.y
            );
            float vel = randRange(system.velRange.x, system.velRange.y);
            float velAngle = angle + randRange(system.initAngleRange.x, system.initAngleRange.y);
            p.velocity = glm::vec2(
                vel * cosf(velAngle),
                vel * sinf(velAngle)
            );
            float accel = randRange(system.accelDeltaRange.x, system.accelDeltaRange.y);
            float accelAngle = velAngle + randRange(system.accelAngleRange.x, system.accelAngleRange.y);
            p.acceleration = glm::vec2(
                accel * cosf(accelAngle),
                accel * sinf(accelAngle)
            );
            activated++;
        }
    }

    // 更新粒子状态
    const float dt = 1.0f / system.frameRate;
    for (auto& p : system.particles) {
        if (p.life > 0 || p.radius > 0) {
            // 数值积分更新
            p.velocity += p.acceleration * dt;
            p.position += p.velocity * dt;
            p.life--;

            // 更新加速度
            p.acceleration += glm::vec2(
                randRange(system.accelDeltaRange.x, system.accelDeltaRange.y),
                randRange(system.accelDeltaRange.x, system.accelDeltaRange.y)
            );
            if (p.life <= 0) {
                p.radius = std::max(p.radius - 1.0f, 0.0f);
            }
        }
    }

    // 准备渲染数据
    std::vector<glm::vec3> renderData;
    renderData.reserve(system.particles.size());
    for (const auto& p : system.particles) {
        renderData.emplace_back(p.position.x, p.position.y, p.radius);
    }

    glEnable(GL_PROGRAM_POINT_SIZE);
    glBlendEquation(GL_FUNC_ADD);

    // 更新VBO数据
    glBindBuffer(GL_ARRAY_BUFFER, system.VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, renderData.size() * sizeof(glm::vec3), renderData.data());

    // 绘制到FBO
    Utils::clearFrame(system.msaaFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, system.msaaFBO);
    glViewport(0, 0, system.width, system.height);
    glUseProgram(shaderProgram);
    glBindVertexArray(system.VAO);

    // 设置统一变量
    GLint locColor = glGetUniformLocation(shaderProgram, "color");
    glUniform4f(locColor,
        system.color.r / 255.0f,
        system.color.g / 255.0f,
        system.color.b / 255.0f,
        system.color.a / 255.0f);
    GLint locProjection = glGetUniformLocation(shaderProgram, "projection");
    glUniformMatrix4fv(locProjection, 1, GL_FALSE, glm::value_ptr(system.projection));

    // 绘制命令
    glEnable(GL_MULTISAMPLE);
    glDrawArrays(GL_POINTS, 0, system.particles.size());
    glDisable(GL_MULTISAMPLE);

    glBindFramebuffer(GL_READ_FRAMEBUFFER, system.msaaFBO);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, system.FBO);
    glBlitFramebuffer(0, 0, system.width, system.height,
        0, 0, system.width, system.height,
        GL_COLOR_BUFFER_BIT, GL_LINEAR);

    // 清理状态
    glBindVertexArray(0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}